// server.c
#include "cmdTask.h"
#include "threadPool.h"
#include <stdio.h>

// 定义一个管道，用于在接收到信号时通知主线程退出
int exitPipe[2];

// 信号处理函数，当接收到指定信号时被调用
void handler(int signum)
{
    // 打印接收到的信号编号
    printf("signum = %d\n", signum);
    // 向管道的写端写入字符 '1'，用于通知主线程
    int res = write(exitPipe[1], "1", 1);
    // 错误检查，如果写入失败则输出错误信息
    if (res == -1)
    {
        perror("handler_write");
    }
}

int main(int argc, char *args[])
{
    // 检查命令行参数数量是否正确，ARGS_CHECK 是自定义的检查宏
    ARGS_CHECK(argc, 4);
    // 创建一个管道，exitPipe[0] 为读端，exitPipe[1] 为写端
    pipe(exitPipe);
    // 创建子进程
    if (fork())
    {
        // 父进程执行此部分
        // 关闭管道的读端，因为父进程只需要写数据
        close(exitPipe[0]);
        // 注册信号处理函数，当接收到 SIGUSR1 信号时调用 handler 函数
        signal(SIGUSR1, handler); // SIGUSR1 = 10
        // 等待子进程结束
        wait(NULL);
        // 父进程退出
        exit(0);
    }

    // 子进程执行此部分
    // 关闭管道的写端，因为子进程只需要读数据
    close(exitPipe[1]);

    // 初始化 TCP 套接字，args[1] 为 IP 地址，args[2] 为端口号
    int sockfd = tcp_init(args[1], args[2]);

    // 定义一个线程池结构体
    threadPool_t pool;
    // 初始化线程池，args[3] 为线程池中的线程数量
    threadPool_init(&pool, atoi(args[3]));

    // 创建一个 epoll 实例，参数 1 表示创建一个大小为 1 的实例
    int epfd = epoll_create(1);

    // 将管道的读端添加到 epoll 实例中，监听读事件
    epollAdd(epfd, exitPipe[0]);

    // 将 TCP 套接字添加到 epoll 实例中，监听读事件
    epollAdd(epfd, sockfd);

    // 定义一个数组，用于存储就绪的 epoll 事件
    struct epoll_event readySet[1024];

    // 进入主循环，不断监听事件
    while (1)
    {
        // 等待 epoll 事件就绪，-1 表示无限等待
        int readyNum = epoll_wait(epfd, readySet, 1024, -1);
        // 遍历所有就绪的事件
        printf("readyNum = %d\n", readyNum);
        for (int i = 0; i < readyNum; ++i)
        {

            // 获取就绪事件对应的文件描述符
            int cfd = readySet[i].data.fd;
            // 如果是 TCP 套接字就绪，说明有新的连接请求
            if (cfd == sockfd)
            {
                int netfd = accept(sockfd, NULL, NULL);
                printf("netfd = %d\n", netfd);
                pthread_mutex_lock(&pool._mutex);

                task_t *newTask = _task_init();
                newTask->_clientFd = netfd;
                _taskQueue_enque(&pool._q, newTask);
                pthread_cond_broadcast(&pool._cond);
                pthread_mutex_unlock(&pool._mutex);
            }
            else if (cfd ==
                     exitPipe[0]) // 如果是管道的读端就绪，说明接收到了退出信号
            {
                // 打印接收到退出信号的信息
                printf("get SIGUSR1\n");
                // 加锁，防止多个线程同时修改线程池的退出标志
                pthread_mutex_lock(&pool._mutex);
                // 设置线程池的退出标志为 1，表示需要退出
                pool._exitFlag = 1;
                // 唤醒所有等待在条件变量上的线程
                pthread_cond_broadcast(&pool._cond);
                // 解锁，允许其他线程访问线程池的任务队列
                pthread_mutex_unlock(&pool._mutex);
                // 遍历线程池中的所有线程
                for (int i = 0; i < pool._tidArr._worker_num; ++i)
                {
                    // 等待线程结束
                    pthread_join(pool._tidArr._arr[i], NULL);
                    // 打印线程退出的信息
                    printf("worker %d exit.\n", i);
                }
                // 打印子进程退出的信息
                printf("subprocess exit.\n");
                // 子进程退出
                exit(0);
            }
        }
    }
}
